﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net;
using System.Security.Principal;
using System.ServiceModel;
using System.Xml;
using Bookvar.ObjectModel.Collections;
using Bookvar.Web.WssListService;
using Bookvar.Web.WssSiteDataService;

namespace Bookvar.Web
{
    public class SharePointService
    {
        public const string TagsSeparator = ",";
        private readonly string domain;
        private readonly string password;
        private readonly string siteUrl;
        private readonly string userName;

        [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#")]
        public SharePointService(string siteUrl, string userName, string password, string domain)
        {
            this.siteUrl = siteUrl;
            this.userName = userName;
            this.password = password;
            this.domain = domain;
        }

        private ListsSoapClient CreateListProxy()
        {
            ListsSoapClient proxy =
                new ListsSoapClient("ListsSoap", new EndpointAddress("http://" + siteUrl + "/_vti_bin/lists.asmx"));
            proxy.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
            proxy.ClientCredentials.Windows.ClientCredential = new NetworkCredential(userName, password, domain);
            return proxy;
        }

        private SiteDataSoapClient CreateSiteDataProxy()
        {
            var proxy = new SiteDataSoapClient( "SiteDataSoap",
                                                new EndpointAddress( "http://" + siteUrl + "/_vti_bin/SiteData.asmx" ) );
            proxy.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
            proxy.ClientCredentials.Windows.ClientCredential = new NetworkCredential(userName, password, domain);
            return proxy;
        }

        [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists"), SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public List<WssList> GetAllLists()
        {
            var result = new List<WssList>();
            SiteDataSoapClient proxy = null;
            try
            {
                proxy = CreateSiteDataProxy();
                _sList[] sLists;
                proxy.GetListCollection(out sLists);
                foreach (_sList sList in sLists)
                {
                    _sListMetadata sListMetadata;
                    _sProperty[] sProperties;
                    proxy.GetList(sList.InternalName, out sListMetadata, out sProperties);
                    bool hasTags = false;
                    foreach (_sProperty sProperty in sProperties)
                    {
                        if (sProperty.Name == "Tags")
                        {
                            hasTags = true;
                        }
                    }
                    var wssList = new WssList(new Guid(sList.InternalName), sList.Title, hasTags);
                    if (wssList.HasTags)
                    {
                        wssList.TagCollection = GetAllTagsForList(wssList.Name, TagsSeparator);
                    }

                    result.Add(wssList);
                }

                return result;
            }
            finally
            {
                if (proxy != null && proxy.State != CommunicationState.Closed)
                {
                    proxy.Close();
                }
            }
        }
        public TagCollection GetAllTagsForList(string listName, string separator)
        {
            var result = new TagCollection();
            string listViewFieldsXml = @"<FieldRef Name=""Tags""/>";
            XmlNode items = GetItems(listName, string.Empty, listViewFieldsXml);
            XmlNamespaceManager nsmgr = CreateListItemNsMgr(items.OwnerDocument.NameTable);
            XmlNodeList tagNodes = items.SelectNodes(@"rs:data/z:row/@ows_Tags", nsmgr);
            
            foreach (XmlNode node in tagNodes)
            {
                foreach (string s in node.Value.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries))
                {
                    result.AddTag(s);
                }
            }

            return result;
        }

        public void UpdateItem(string listName, string id, string tags)
        {
            ListsSoapClient proxy = null;
            try
            {
                proxy = CreateListProxy();
                XmlDocument doc = new XmlDocument();
                XmlElement batchElement = doc.CreateElement("Batch");
                batchElement.SetAttribute("OnError", "Continue");
                //batchElement.SetAttribute("ListVersion", "1");
                //batchElement.SetAttribute("ViewName", "{7137FFF8-48FF-4C69-8C76-0E3BBD1EA7F9}");

                /*Specify methods for the batch post using CAML. In each method 
                 include the ID of the item to update and the value to place in the 
                 specified column.*/
                batchElement.InnerXml = string.Format(CultureInfo.InvariantCulture, "<Method ID='1' Cmd='Update'>" +
                                        "<Field Name='ID'>{0}</Field>" +
                                        "<Field Name='Tags'>{1}</Field></Method>", id, tags);

                /*Update list items. This example uses the list GUID, 
                 which is recommended, but the list display name will also work.*/
                proxy.UpdateListItems(listName, batchElement);
            }
            finally
            {
                if (proxy != null && proxy.State != CommunicationState.Closed)
                {
                    proxy.Close();
                }
            }
        }
        public void UpdateTags(string listName, string fileName, string tags)
        {
            string id = GetItemId(listName, fileName);
            UpdateItem(listName, id, tags);
        }
        public string GetItemId(string listName, string fileName)
        {
            string listQueryXml = string.Format(CultureInfo.InvariantCulture, @"<Where><Contains><FieldRef Name=""FileLeafRef""/><Value Type=""File"">{0}</Value></Contains></Where>", fileName);
            string listViewFieldsXml = @"<FieldRef Name=""Tags""/>";
            //XmlNameTable nameTable 
            
            XmlNode node = GetItems(listName, listQueryXml, listViewFieldsXml);
            XmlNamespaceManager nsmgr = CreateListItemNsMgr(node.OwnerDocument.NameTable);
            XmlNode idNode = node.SelectSingleNode(@"rs:data/z:row/@ows_ID", nsmgr);
            string id = idNode.Value;

            return id;
        }

        private static XmlNamespaceManager CreateListItemNsMgr(XmlNameTable nameTable)
        {
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(nameTable);
            nsmgr.AddNamespace("my", "http://schemas.microsoft.com/sharepoint/soap/");
            nsmgr.AddNamespace("z", "#RowsetSchema");
            nsmgr.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
            nsmgr.AddNamespace("dt", "uuid:C2F41010-65B3-11d1-A29F-00AA00C14882");
            nsmgr.AddNamespace("s", "uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882");
            return nsmgr;
        }

        private XmlNode GetItems(string listName, string listQueryXml, string listViewFieldsXml)
        {
            ListsSoapClient proxy = null;
            try
            {
                proxy = CreateListProxy();
                XmlDocument doc = new XmlDocument();

                XmlElement listQuery = doc.CreateElement("Query");
                listQuery.InnerXml = listQueryXml;

                XmlElement listViewFields = doc.CreateElement("ViewFields");
                listViewFields.InnerXml = listQueryXml;

                XmlElement listQueryOptions = doc.CreateElement("QueryOptions");
                listQueryOptions.InnerXml = listViewFieldsXml;

                Guid g = GetWebID();

                XmlNode items =
                    proxy.GetListItems(listName, string.Empty, listQuery, listViewFields, string.Empty, listQueryOptions,
                                       g.ToString());
                return items;
            }
            finally
            {
                if (proxy != null && proxy.State != CommunicationState.Closed)
                {
                    proxy.Close();
                }
            }
        }

        private Guid GetWebID()
        {
            SiteDataSoapClient proxy = null;
            try
            {
                proxy = CreateSiteDataProxy();

                _sWebMetadata webMetaData;

                _sWebWithTime[] arrWebWithTime;

                _sListWithTime[] arrListWithTime;

                _sFPUrl[] arrUrls;

                string roles;
                ArrayOfString roleUsers;
                ArrayOfString roleGroups;

                proxy.GetWeb(out webMetaData, out arrWebWithTime, out arrListWithTime, out arrUrls, out roles,
                             out roleUsers, out roleGroups);

                Guid g = new Guid(webMetaData.WebID);

                return g;
            }
            finally
            {
                if (proxy != null && proxy.State != CommunicationState.Closed)
                {
                    proxy.Close();
                }
            }
        }

        /*
        private System.Xml.XmlNode GetItems(string webPath)
        {

            ListsOnLocalhost.Lists listsWS = new Sharepoint_Unit_Tests.ListsOnLocalhost.Lists();

            listsWS.Url = webPath + "/_vti_bin/lists.asmx";

            listsWS.UseDefaultCredentials = true;

            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();

            doc.LoadXml("");

            System.Xml.XmlNode listQuery = doc.SelectSingleNode("//Query");

            System.Xml.XmlNode listViewFields = doc.SelectSingleNode("//ViewFields");

            System.Xml.XmlNode listQueryOptions = doc.SelectSingleNode("//QueryOptions");

            Guid g = GetWebID(webPath);

            System.Xml.XmlNode items = listsWS.GetListItems(listName.Text, string.Empty, listQuery, listViewFields, string.Empty, listQueryOptions, g.ToString());

            return items;

        }





        private Guid GetWebID(string webPath)
        {

            SiteDataWebService.SiteData siteDataWS = new SiteDataWebService.SiteData();

            siteDataWS.UseDefaultCredentials = true;

            SiteDataWebService._sWebMetadata webMetaData;

            SiteDataWebService._sWebWithTime[] arrWebWithTime;

            SiteDataWebService._sListWithTime[] arrListWithTime;

            SiteDataWebService._sFPUrl[] arrUrls;

            string roles; string[] roleUsers; string[] roleGroups;

            siteDataWS.Url = webPath + "/_vti_bin/sitedata.asmx";

            uint i = siteDataWS.GetWeb(out webMetaData, out arrWebWithTime, out arrListWithTime, out arrUrls, out roles, out roleUsers, out roleGroups);

            Guid g = new Guid(webMetaData.WebID);

            return g;

        }*/
    }
}